/*
 * This file is part of cve-check-tool
 * Copyright (C) 2015 Intel Corporation
 *
 * cve-check-tool is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

#define _GNU_SOURCE
#include <check.h>
#include <stdio.h>
#include <stdlib.h>

#include "cve-string.c"
#include "hashmap.c"
#include "template.c"

#include "config.h"

START_TEST(cve_template_basic)
{
        cve_string *ret = NULL;
        GHashTable *table = NULL;

        const char *unchanged = "I have no {{hashtable}}";
        ret = template_string(unchanged, NULL);
        fail_if(!ret, "No return string");
        fail_if(!cve_string_const_equal(ret, unchanged), "Differing string for no hashtable");
        cve_string_free(ret);

        table = g_hash_table_new(g_str_hash, g_str_equal);
        fail_if(!table, "Unable to allocate table");

        g_hash_table_insert(table, "key1", "Frodo");
        g_hash_table_insert(table, "key2", " Baggins");
        g_hash_table_insert(table, "key3", "Hobbit");
        g_hash_table_insert(table, "location", "Mordor");

        const char *str =
            "{{key1}}{{key2}} was a curious {{key3}}. With hindsight it is likely he would have avoided {{location}}.";
        const char *exp =
            "Frodo Baggins was a curious Hobbit. With hindsight it is likely he would have avoided Mordor.";
        ret = template_string(str, table);
        fail_if(!ret, "Unable to allocate string");
        fail_if(!cve_string_const_equal(ret, exp), "Built string does not match expected template output");
        cve_string_free(ret);

        g_hash_table_unref(table);
}
END_TEST

START_TEST(cve_template_context)
{
        TemplateContext *top = NULL;
        TemplateContext *child = NULL;
        cve_string *ret = NULL;

        top = template_context_new();
        fail_if(!top, "Failed to allocate TemplateContext");
        template_context_add_string(top, "name", "correctname");

        child = template_context_new();
        fail_if(!child, "Failed to allocate TemplateContext");
        template_context_add_string(child, "number", "42");
        template_context_add_subcontext(top, "section", child);

        const char *input =
            "The name is {{name}}{{#norender}}Output{{/norender}}{{#section}} {{name}} {{number}}{{/section}}";
        const char *exp = "The name is correctname correctname 42";

        ret = template_context_process_line(top, input, false);
        fail_if(!ret, "Failed to get return fro template_context_process_line");
        fail_if(!cve_string_const_equal(ret, exp), "Returned context string does not match expected template output");
        cve_string_free(ret);

        /* HTMLish */
        input = "table a:visited { color: #999999 ; }";
        ret = template_context_process_line(top, input, false);
        fail_if(!cve_string_const_equal(ret, input),
                "Returned context string does not match expected Style template output");
        cve_string_free(ret);

        template_context_free(top);

        /* bool checks */
        top = template_context_new();
        input =
            "{{#bool1}}Hello Universe{{/bool1}}{{#bool2}}Hello World{{/bool2}}{{#ignored}}Should not emit{{/ignored}}";
        exp = "Hello World";
        template_context_add_bool(top, "bool1", false);
        template_context_add_bool(top, "bool2", true);
        ret = template_context_process_line(top, input, false);
        fail_if(!cve_string_const_equal(ret, exp), "Return context (boolean) string does not match expected output");
        cve_string_free(ret);

        template_context_free(top);
}
END_TEST

START_TEST(cve_template_fails)
{
        cve_string *ret = NULL;
        GHashTable *table = NULL;

        table = g_hash_table_new(g_str_hash, g_str_equal);
        fail_if(!table, "Unable to allocate table");

        g_hash_table_insert(table, "failure", "onoes");

        const char *msg = "This is {{failure 1";
        /* Expected this will be stripped */
        const char *exp = "This is {{failure 1";
        ret = template_string(msg, table);
        fail_if(!ret, "Unable to allocate string");
        fail_if(!cve_string_const_equal(ret, exp), "Differing return string");
        cve_string_free(ret);

        msg = "This is {{failure }2";
        exp = "This is {{failure }2";
        ret = template_string(msg, table);
        fail_if(!ret, "Unable to allocate string");
        fail_if(!cve_string_const_equal(ret, exp), "Differing return string #2");
        cve_string_free(ret);

        msg = "This is {{failure}} {{test}}!";
        exp = "This is onoes !";
        ret = template_string(msg, table);
        fail_if(!ret, "Unable to allocate string");
        fail_if(!cve_string_const_equal(ret, exp), "Unknown value not collapsed");
        cve_string_free(ret);

        g_hash_table_unref(table);
}
END_TEST

START_TEST(cve_template_list)
{
        TemplateContext *top = NULL;
        TemplateContext *node = NULL;
        const char *exp = NULL;
        cve_string *ret = NULL;

        top = template_context_new();
        fail_if(!top, "Failed to allocate TemplateContext");

        node = template_context_new();
        template_context_add_string(node, "key1", "val1");
        fail_if(!template_context_add_list(top, "list", node), "Failed to add node to list");

        node = template_context_new();
        template_context_add_string(node, "key1", "val2");
        fail_if(!template_context_add_list(top, "list", node), "Failed to add node to list");

        node = template_context_new();
        template_context_add_string(node, "key1", "val3");
        fail_if(!template_context_add_list(top, "list", node), "Failed to add node to list");

        exp = "list items: val1 val2 val3 ";
        ret = template_context_process_line(top, "list items: {{#list}}{{key1}} {{/list}}", false);
        fail_if(!ret, "No return from template_context_process_line");
        fail_if(!cve_string_const_equal(ret, exp), "Returned list string does not match expected output");
        cve_string_free(ret);

        template_context_free(top);
}
END_TEST

START_TEST(cve_template_bool)
{
        TemplateContext *top = NULL;
        const char *exp = NULL;
        cve_string *ret = NULL;

        top = template_context_new();
        fail_if(!top, "Failed to allocate TemplateContext");

        template_context_add_bool(top, "conditiontrue", true);
        template_context_add_string(top, "name", "Frodo");

        exp = "His name was Frodo: true";
        ret = template_context_process_line(
            top,
            "His name was {{#conditiontrue}}{{name}}{{/conditiontrue}}{{#nocond}}Jimbob{{/nocond}}: {{conditiontrue}}",
            false);
        fail_if(!ret, "No return from template_context_process_line");
        fail_if(!cve_string_const_equal(ret, exp), "Returned bool-test string does not match expected output");
        cve_string_free(ret);

        template_context_free(top);
}
END_TEST
static Suite *core_suite(void)
{
        Suite *s = NULL;
        TCase *tc = NULL;

        s = suite_create("cve_template");
        tc = tcase_create("cve_template_functions");
        tcase_add_test(tc, cve_template_basic);
        tcase_add_test(tc, cve_template_fails);
        tcase_add_test(tc, cve_template_context);
        tcase_add_test(tc, cve_template_list);
        tcase_add_test(tc, cve_template_bool);
        suite_add_tcase(s, tc);

        return s;
}

int main(void)
{
        Suite *s;
        SRunner *sr;
        int fail;

        s = core_suite();
        sr = srunner_create(s);
        srunner_run_all(sr, CK_VERBOSE);
        fail = srunner_ntests_failed(sr);
        srunner_free(sr);

        if (fail > 0) {
                return EXIT_FAILURE;
        }

        return EXIT_SUCCESS;
}

/*
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
 *
 * Local variables:
 * c-basic-offset: 8
 * tab-width: 8
 * indent-tabs-mode: nil
 * End:
 *
 * vi: set shiftwidth=8 tabstop=8 expandtab:
 * :indentSize=8:tabSize=8:noTabs=true:
 */
